ENSO:A Streaming Interface for NIC-Application Communication——2023

摘要

现代NIC实现了硬件offload(例如:https://en.wikipedia.org/wiki/TCP_offload_engine),现代软件采用了批量化IO的技术。这些技术与NIC的分组接口不再匹配。所谓分组接口是指,软件与NIC的接口是发送/接收一系列固定大小的缓冲区(例如一个MTU大小的分组)。这种不匹配限制了通信效率和性能。

本文的核心是取消了分组接口,使用机构化的通信方式像流一样可以发送任意大小的数据。

论文研究目标

问题

  1. 分组接口。当使用该接口时,NIC必须要把大于缓存大小的消息拆分成多个报文。这样做要么要求它们首先将数据复制到单独的缓冲区,要么要求应用程序逻辑本身被设计为处理打包的数据。实际上,在实现分组化接口的NIC中实现处理多于单个分组的数据的任何卸载或抽象(例如,提供字节流抽象的传输协议,诸如TCP)需要将数据从分组缓冲器复制到流。这种额外的拷贝可能会增加大量开销,从而抵消了此类分流的一些好处
  2. 缓存失效:由于分组化接口迫使传入和传出的数据分散在内存中,它限制了预取器和其他CPU优化的有效性,这些优化需要预测软件将访问的下一个内存地址--我们将这种现象称为混乱内存访问。
  3. 元数据负载(其实就是描述符):由于分组化接口依赖于每个数据包的元数据,因此它花费了PCIe带宽的很大一部分来传送元数据-在使用小消息时高达可用带宽的39%。这会导致处理小请求的应用程序受到PCIe的瓶颈,从而阻止它们扩展到超过一定数量的核心。每包元数据的使用还增加软件发送和接收数据所需的存储器访问次数,从而进一步减少应用程序可用的周期。

贡献

Ens̄o提供流抽象,NIC和应用程序可以使用该抽象来传递任意大小的数据块

ENS̄o将缓冲区视为不透明数据,并且不对其内容、结构或大小施加任何要求,从而允许它们用于传输任意数据,其大小可以与环形缓冲区本身一样大。ENS̄o还显著减少了由于元数据造成的PCIE带宽开销,因为它能够聚合写入同一缓冲区的多个数据块的通知。

方法

目标

  1. 灵活性
  2. 低软件负载
  3. 低硬件复杂度

ENS̄o是围绕ENS̄o Pipe设计的,这是一种新的缓冲区抽象,允许应用程序和NIC交换任意数据块,就像对无限内存缓冲区进行读写一样。与分组化接口使用的环形缓冲器(其保存描述符到分散的分组缓冲器)不同,ENS̄管道被实现为包含实际分组数据的数据环形缓冲器。

Overview

  1. 假设有两个Pipe来接收数据A和B,最开始都是空的, HEADSWTailNIC都指向数据缓冲区的开头
  2. 当NIC收到数据之后,把数据分片填充到Pipe A和Pipe B,其中A填充了两条数据,B填充了3条数据。NIC发送两个通知(一个PIPE各一个),软件使用这些通知移动TailNIC并开始处理数据
  3. 一旦数据处理完毕,软件就通过MMIO修改寄存器,移动HEADSW

Ens̄o管道的不透明性意味着它们可以映射到应用程序内存空间中的任何固定内存。因此,通过将RX和TX ENS̄0管道映射到同一区域,网络功能和其他转发应用可以避免复制分组。

尽管实现用于数据传输的环形缓冲区本身是一个简单的想法,但事实证明,协调CPU和NIC之间的通知以更新头指针和尾指针是具有挑战性的。

Efficient Notifications

ENSO 设计了通知缓冲区来通知指针的修改。

Notifications包含给定的Pipe的最新的TailNIC,以及一个flag,软件可以检查该flag看是否可以被处理。软件通过MMIO的方式修改NotificationHeadSW

多路复用

在一个线程内部,只有一个Notification Buffer,可以为多个PIPE提供服务,为了区分不同的PIPE,每个TailNIC包含一个PIPE ID。

多线程:为了让多个线程独立发送和接收数据,ens̄o支持多个通知缓冲区。每个线程都可以使用专用的通知缓冲区,从而避免了昂贵的同步原语。在设置新的ENS̄o管道时,软件会告诉NIC与其关联的通知缓冲区。因此,NIC知道将通知发送到哪个通知缓冲区。

多进程:除了使用独立的通知缓冲区之外,ENS̄o还确保应用程序只能访问它们自己的Es̄o管道和通知缓冲区的子集。每个队列的MMIO指针寄存器对保存在其自己的专用页面对齐的内存块中

Pacing Notifications

批量提交notifications,以减少元数据的带宽占用。但是批量大小的确定是很困难的。

我们采用的方法是:当软件通过MMIO更新HeadSW时,就说明已经有数据被处理完了,此时就发送通知。此外每个PIPE都有一个status用于指示是否有数据,如果status为0也立即发送通知。

实现

软件实现

  1. library向内核申请缓冲区,内核在NIC上分配空间,并将他们映射到进程空间
  2. 为了防止一次数据写入跨越了缓冲区的边界,我们将同一块物理内存在进程空间映射了两次,因此虚拟地址空间的大小是物理空间的两倍;我们的library会自动检测数据是否越过了缓冲区边界,然后将他们拆分为若干次transfers。

所以既然是拆分了,为啥还要映射两次呢?另外,所有的数据都位于同一个连续的缓冲区中,那么如何确定应用层的数据边界呢?

硬件实现

RX

NS̄o管道管理器负责保持ENS̄o管道状态,例如缓冲区的物理地址、HeadSW、TailNIC、通知缓冲区ID和通知状态位。

为了触发通知,管理器包括通知缓冲区ID,并在发送到通知缓冲区管理器的元数据中设置一个位。

单个通知管理器也是足够的,因为我们使用比ENTCPUO管道更少的通知缓冲区,例如,每CPU核一个通知缓冲区。我们的实现默认使用128个通知缓冲区,但也满足1024个通知缓冲区的计时要求。

TX

当软件将新的TX通知入队并使用MMIO写入NotificationTailSW时,管理器请求DMA读取以从存储器获取通知。读请求被发送到DMA引擎,该引擎将对通知FIFO的DMA读响应排队。然后,管理器可以使用通知,从而允许它请求对ens̄o管道中的实际数据进行直接存储器访问读取。它还将有关每个数据请求的信息发送到完成监视器模块。

当TX通知缓冲区管理器请求的数据到达时,DMA引擎将其入队到数据FIFO中。完成监视器消费数据,并使用从TX通知缓冲区管理器获得的信息跟踪每个请求中待处理的字节数。当请求完成时,完成监视器向DMA引擎发送TX完成通知,并将其写入主机内存。然后,它可以将数据和元数据(包括Ens ̄ o管道ID和大小)输出到NIC的下游模块。

配置通知(Configuration Notifications)将排队到配置FIFO,而不是通知FIFO。这些数据由配置器使用,配置器将配置定向到NIC上的相应模块。例如,当内核设置新的ENS̄o管道时,它会在NIC流表中插入一个条目,以将一组数据包定向到它。

用例

Traditional NIC

对于执行简单卸载(如校验和和分段)的传统NIC而言,使用ENS̄o与使用分组化接口没有显著区别。在这两种情况下,网络堆栈都是在软件中实现的,只需更改为使用ENS̄o管道。

NIC with transport offload

实现基于消息的传输(例如,SCTP、HOMA[60])或基于流的传输(例如,tcp)的NIC也可以选择使用ENS̄管道来将消息或重组的字节流直接传递到应用程序,而无需复制。

NIC with application logic

实现应用层协议或包含部分应用程序逻辑的网络接口卡(NIC)可以使用Ens ̄ o管道与应用程序进行应用级消息交换。例如,一个既了解TCP又了解HTTP的NIC可以将传入的HTTP请求直接传递给Web服务器,有效地将应用程序转换为按顺序执行的模型。

实验

结论

未来与展望

强相关参考论文

论文名称 摘要/说明

其它相关材料

请 Ta 喝咖啡 ☕️